#pragma once

#ifndef DECK_H
#define DECK_H

#include <vector>
#include <algorithm>
#include <functional>   

///////////////////////////////////////////////////////////////////////////////
/////                            CCard                                    /////
///////////////////////////////////////////////////////////////////////////////

class CCard
{
public:
    enum Suit 
    {
        Hearts = 0, Diamonds, Clubs, Spades
    };
    
    enum Value 
    {
        Two = 2, Three, Four, Five, Six, Seven, 
        Eight, Nine, Ten, Jack, Queen, King, Ace
    };

    CCard(Suit suit, Value value):
        mSuit(suit), mValue(value)
    {};

    explicit CCard(int cardIndex):
        mSuit(Suit(cardIndex / 13)), mValue(Value(cardIndex%13+Two))
        {};

    Suit getSuit()   const { return mSuit; };
    Value getValue() const { return mValue; };
    int getIndex()   const { return mSuit*13 + mValue - Two; };

    class Value_eq: public std::unary_function<CCard, bool>
    {
    public:
        explicit Value_eq(const Value value):
            mValue(value) {};

        bool operator() (const CCard& card) const
        {
            return ( card.mValue == mValue );
        };
    private:
        Value mValue;
    };

    class Value_less: public std::unary_function<CCard, bool>
    {
    public:
        explicit Value_less(const Value value):
            mValue(value) {};

        bool operator() (const CCard& card) const
        {
            return ( mValue < card.mValue );
        };
    private:
        Value mValue;
    };

    struct Value_cmp: public std::unary_function<CCard, bool>
    {
        bool operator() (const CCard& card1, const CCard& card2) const
        {
            return ( card1.mValue < card2.mValue );
        };
    };


    static bool equalSuit(const CCard& card1, const CCard& card2)
    {
        return ( card1.mSuit == card2.mSuit );
    };

    static bool equalValue(const CCard& card1, const CCard& card2)
    {
        return ( card1.mValue == card2.mValue );
    };

private:
    Suit mSuit;
    Value mValue;

    friend bool operator== (const CCard& rhs, const CCard& lhs);
    friend bool operator< (const CCard& rhs, const CCard& lhs);
};

inline bool operator== (const CCard& rhs, const CCard& lhs)
{
    return ( rhs.getIndex() == lhs.getIndex() );
};

inline bool operator< (const CCard& rhs, const CCard& lhs)
{
    return ( rhs.getIndex() < lhs.getIndex() );
};

typedef std::vector<CCard> Cards;
typedef std::vector<CCard>::const_iterator CardsConstIterator;
typedef std::vector<CCard>::iterator CardsIterator;

///////////////////////////////////////////////////////////////////////////////
/////                            CCards                                   /////
///////////////////////////////////////////////////////////////////////////////

class CCards
{
public:
    CCards(unsigned int capacity)
    {
        mCards.reserve(capacity);
    };

    CCards& operator-= (const CCard& card)
    {
        mCards.erase( std::find( mCards.begin(), mCards.end(), card ) );
        return (*this);
    };

    CCards& operator+= (const CCard& card)
    {
        mCards.push_back( card );
        return (*this);
    };

    void dealCard(const CCard& card, CCards& to)
    {
        operator -=(card);
        to += card;
    };

    void sort()
    {
        std::sort(mCards.begin(), mCards.end(), CCard::Value_cmp());
    };


//protected:
    Cards mCards;
};

///////////////////////////////////////////////////////////////////////////////
/////                            CDeck                                    /////
///////////////////////////////////////////////////////////////////////////////

class CDeck: public CCards
{
public:
    CDeck() :
      CCards(52)
    {
        for (int i = 0; i < 52; i++)
            operator+=( CCard(i) );
    };
};

///////////////////////////////////////////////////////////////////////////////
/////                            CHand                                    /////
///////////////////////////////////////////////////////////////////////////////

class CHand: public CCards
{
public:
    CHand():
      CCards(2)
    {};
private:

};

///////////////////////////////////////////////////////////////////////////////
/////                            CBoard                                   /////
///////////////////////////////////////////////////////////////////////////////

class CBoard: public CCards
{
public:
    CBoard():
      CCards(5)
    {};
private:

};

///////////////////////////////////////////////////////////////////////////////
/////                            CTable                                   /////
///////////////////////////////////////////////////////////////////////////////

class CTable
{
public:
    CTable()
    {

    };

    void dealToHand(const CCard& card)
    {
        mDeck.dealCard(card, mHand);
    };

private:
    CDeck  mDeck;
    CBoard mBoard;
    CHand  mHand;
};


#endif   // DECK_H